package com.hckjsec.cloud.WebSocket;

import com.alibaba.fastjson.JSON;
import com.hckjsec.cloud.domain.videoView.WebSocketUser;
import com.hckjsec.common.core.redis.RedisCache;
import com.hckjsec.common.utils.ComUtil;
import com.hckjsec.common.utils.StringUtils;
import com.hckjsec.common.utils.http.HttpUtils;
import com.hckjsec.common.utils.spring.SpringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Created by huiyunfei on 2019/5/31.
 */

@ServerEndpoint("/cloud/websocket/{sid}")
@Component
public class WebSocketServer {
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    private static ConcurrentHashMap<String, List<WebSocketUser>> RoomByUserListHt= new ConcurrentHashMap<String, List<WebSocketUser>>();
    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    //接收sid
    private String sid = "";
    //连接建立成功调用的方法
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        webSocketSet.add(this);     //加入set中
        WebSocketUser webSocketUser= SpringUtils.getBean(RedisCache.class).getCacheObject(ComUtil.getWechatVideoRoomCacheKey(sid));//根据sid获取房间号
        addOnlineCount(webSocketUser);           //在线数加1
        this.sid=sid;
        try {
            sendMessage(new WebSocketMessage("连接成功"));
        } catch (IOException e) {
            log.error("websocket IO异常");
        }
    }


    //进入房间
    public static synchronized void addOnlineCount(WebSocketUser webSocketUser) {
        String roomId=webSocketUser.getRoomId();
        List<WebSocketUser> userList= new ArrayList<>();
        if(!StringUtils.isNull(RoomByUserListHt.get(roomId))) {
            userList=RoomByUserListHt.get(roomId);
        }
        userList.add(webSocketUser);
        //去重
        userList.sort(Comparator.comparing(WebSocketUser::getSid).reversed());
        userList = removeDuplicateOutputField(userList);
        RoomByUserListHt.put(roomId,userList);
        String msg=webSocketUser.getUserName();
        if ("web".equals(webSocketUser.getLx())){
            msg=msg+"(电脑端)";
        }else{
            msg=msg+"(手机端)";
            String message="用户【"+webSocketUser.getUserName()+"】进入了房间。";
            WebSocketMessage webSocketMessage= new WebSocketMessage("web","notice",message);
            sendInfo(webSocketMessage,getWebSidList(userList,"web"));
        }
        log.info("房间号:"+roomId+",【"+msg+"】进入了房间,当前房间人员:"+getNameList(userList));
    }
    //离开房间
    public static synchronized void subOnlineCount(WebSocketUser webSocketUser) {
        String roomId=webSocketUser.getRoomId();
        List<WebSocketUser> userList= RoomByUserListHt.get(roomId);
        if (StringUtils.isNotEmpty(userList)) {
            Iterator<WebSocketUser> it = userList.iterator();
            while (it.hasNext()) {
                WebSocketUser webSocketUser1 = it.next();
                if (webSocketUser.getSid().equals(webSocketUser1.getSid())) {
                    it.remove();
                }
            }
            RoomByUserListHt.put(roomId, userList);
            if (StringUtils.isEmpty(userList)) {
                RoomByUserListHt.remove(roomId);
            }
            String msg = webSocketUser.getUserName();
            if ("web".equals(webSocketUser.getLx())) {
                msg = msg + "(电脑端)";
            } else {
                msg = msg + "(手机端)";
                String message = "用户【" + webSocketUser.getUserName() + "】离开了房间。";
                WebSocketMessage webSocketMessage = new WebSocketMessage("web", "notice", message);
                sendInfo(webSocketMessage, getWebSidList(userList, "web"));
            }
            log.info("房间号:" + roomId + ",【" + msg + "】离开了房间,当前房间人员:" + getNameList(userList));
        }
    }

    public  static synchronized void sendSign(String roomId){
        List<WebSocketUser> userList= RoomByUserListHt.get(roomId);
        WebSocketMessage webSocketMessage= new WebSocketMessage("applets","sign","");
        sendInfo(webSocketMessage,getWebSidList(userList,"applets"));
    }

    public  static synchronized void sendSignMsg(String roomId,String userName){
        String message="用户【"+userName+"】已完成签署。";
        List<WebSocketUser> userList= RoomByUserListHt.get(roomId);
        WebSocketMessage webSocketMessage= new WebSocketMessage("web","docnotice",message);
        sendInfo(webSocketMessage,getWebSidList(userList,"web"));
    }

    public  static synchronized void closeRoom(String roomId){
        List<WebSocketUser> userList= RoomByUserListHt.get(roomId);
        WebSocketMessage webSocketMessage= new WebSocketMessage("applets","close","");
        sendInfo(webSocketMessage,getWebSidList(userList,"applets"));
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        WebSocketUser webSocketUser=SpringUtils.getBean(RedisCache.class).getCacheObject(ComUtil.getWechatVideoRoomCacheKey(sid));//根据sid获取房间号
        subOnlineCount(webSocketUser);           //在线数减1
    }
    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }



    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到来自窗口"+sid+"的信息:"+message);
        //群发消息
//        for (WebSocketServer item : webSocketSet) {
//            try {
//                if(sid==null) {
//                    item.sendMessage(message);
//                }else if(item.sid.equals(sid)){
//                    item.sendMessage(message);
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
    }


    /**
     * 群发自定义消息
     * */
    public static void sendInfo(Object object,List<String> sidList) {
        for (WebSocketServer item : webSocketSet) {
            try {
                if(sidList.contains(item.sid)){
                    item.sendMessage(object);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

   /**
     * 实现服务器主动推送
     **/
    public void sendMessage(Object object) throws IOException {
        String message=JSON.toJSONString(object);
        this.session.getBasicRemote().sendText(message);
    }

    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }

    /**
     * 根据list中对象某些字段去重
     * @param list 需要去重的list
     * @return 返回去重后的list
     */
    private static synchronized List<WebSocketUser> removeDuplicateOutputField(List<WebSocketUser> list) {
        Set<WebSocketUser> set = new TreeSet<>(new Comparator<WebSocketUser>() {
            public int compare(WebSocketUser webSocketUser, WebSocketUser webSocketUserNew) {
                int compareToResult = 1;//==0表示重复
                if(StringUtils.equals(webSocketUser.getSid(), webSocketUserNew.getSid()) &&
                        StringUtils.equals(webSocketUser.getRoomId(), webSocketUserNew.getRoomId())) {
                    compareToResult = 0;
                }
                return compareToResult;
            }
        });
        set.addAll(list);
        return new ArrayList<>(set);
    }
    /**
     * 根据list中获取房间人
     * @param list 需要去重的list
     * @return 返回去重后的list
     */
    private static synchronized String getNameList(List<WebSocketUser> list) {
        String msg="";
        List<String> nameList=new ArrayList<>();
        if (list.size()>0){
            list.forEach(kv->{
                nameList.add(kv.getUserName());
            });
            msg=StringUtils.join(nameList.toArray(),",");
        }else{
            msg="无";
        }
        return msg;
    }

    /**
     * 根据list中获取电脑端sid和手机端
     * @param list 需要去重的list
     * @return 返回去重后的list
     */
    private static synchronized List<String> getWebSidList(List<WebSocketUser> list,String type) {
        List<String> sidList=new ArrayList<>();
        if (StringUtils.isNotEmpty(list)) {
            list.forEach(kv->{
                if (type.equals(kv.getLx())){
                    sidList.add(kv.getSid());
                }
            });
        }
        return sidList;
    }
}